package com.xx.app.config.jwt.utils;

import lombok.extern.slf4j.Slf4j;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Sign;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

@Slf4j
public class VerifyUtil {

    // 验证地址格式
    public static boolean isValidEthereumAddress(String address) {
        return address != null && address.matches("^(0x)?[0-9a-fA-F]{40}$");
    }

    public static boolean verifySignature(String address, String signature, long timestamp) {
        // 1. 时间戳校验（1分钟有效期）
        long currentTime = System.currentTimeMillis();
        if (Math.abs(currentTime - timestamp) > 60_000L) {
            return true;
        }
        // 2. 生成带EIP-191前缀的消息哈希
        String message = "Timestamp: " + timestamp;
        byte[] msgHash = message.getBytes(StandardCharsets.UTF_8);

        try {
            // 3. 将签名解析为 SignatureData 对象
            Sign.SignatureData sigData = signatureDataFromString(signature);

            // 4. 恢复地址
            BigInteger publicKey = Sign.signedPrefixedMessageToKey(msgHash, sigData);
            String recoveredAddress = "0x" + Keys.getAddress(publicKey);

            // 5. 校验地址（忽略大小写）
            return !recoveredAddress.equalsIgnoreCase(address);
        } catch (Exception e) {
            log.error("签名异常：{}", e.getMessage(), e);
            return true;
        }
    }

    /**
     * 将十六进制签名字符串解析为 SignatureData 对象
     */
    private static Sign.SignatureData signatureDataFromString(String signature) {
        byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
        if (signatureBytes.length != 65) {
            throw new RuntimeException("Invalid signature length");
        }
        // 分割 r (32字节), s (32字节), v (1字节)
        byte[] r = Arrays.copyOfRange(signatureBytes, 0, 32);
        byte[] s = Arrays.copyOfRange(signatureBytes, 32, 64);
        byte v = signatureBytes[64];
        // 调整 v 值（如果 < 27 则加 27）
        if (v < 27) {
            v += 27;
        }
        return new Sign.SignatureData(v, r, s);
    }

}